use syn::{File, Item, ItemFn, FnArg, Block, Expr, Pat, Type, Ident, Macro, ItemStruct, ItemEnum, ItemType, ItemStatic, ItemMacro, UseTree};
use quote::quote;
use syn::token::Fn;
use tempfile::NamedTempFile;
use std::process::Command;
use std::env;
use std::fs;
use std::collections::{HashSet, HashMap};
use std::io::Write;

fn is_empty_function(func: &ItemFn) -> bool {
    // 检查函数体是否为空
    let block = &func.block;
    // 如果函数体为空，返回 true
    return block.stmts.is_empty();
    // 如果没有函数体，返回 true
    //true
}

fn remove_whitespace(s: &str) -> String {
    // 去除字符串中的所有空白符（空格、换行符、制表符等）
    s.chars().filter(|c| !c.is_whitespace()).collect()
}

fn main() {
    // 获取传递的文件名
    let args: Vec<String> = env::args().collect();
    if args.len() < 3 {
        eprintln!("Usage: remove-funcdecl/target/debug/remove-funcdecl --<filename> --<symbolfile>");
        return;
    }
    let filename = &args[1];
    // 读取全局符号文件
    let global_symbols_filename = &args[2];
    let global_symbols_code = fs::read_to_string(global_symbols_filename).expect("Unable to read global symbols file");
    
    // 解析全局符号文件，提取函数名
    let global_symbols_ast: File = syn::parse_str(&global_symbols_code).expect("Unable to parse global symbols file");
    let mut global_symbols = HashSet::new();

    for item in global_symbols_ast.items {
        if let Item::Fn(func) = item {
            let ident = func.sig.ident.to_string();
            let func_str = quote! { #func }.to_string();
            let func_str_no_whitespace = remove_whitespace(&func_str);
            global_symbols.insert(func_str_no_whitespace);
        }
    }


    // 读取文件内容
    let input_code = fs::read_to_string(filename).expect("Unable to read file");

    // 解析 Rust 代码
    let ast: File = syn::parse_str(&input_code).expect("Unable to parse Rust code");

    // 用于存储已经遇到定义名称
    let mut seen_definitions = HashSet::new();

    // 用于存储已经遇到的 use 语句
    let mut seen_use_statements = HashSet::new();

    // 用于存储函数定义，后面的函数定义会覆盖前面的
    //let mut function_definitions = HashMap::new();
    let mut function_definitions = Vec::new();

    // 用于存储其他定义（结构体、枚举、类型定义、全局变量、宏定义）
    let mut other_definitions = Vec::new();
    
    // 过滤掉空函数定义，并且对于同名的函数，只保留最后出现的函数
    //let filtered_items: Vec<Item> = ast.items
    //    .into_iter()
    //    .filter(|item| {
    for item in ast.items {
        match item {
            Item::Fn(func) => { 
                // 获取函数名
                let ident = func.sig.ident.to_string();
                // 检查是否为空函数
                if is_empty_function(&func) {
                    // 如果是空函数，直接跳过
                    //return false;
                    continue;
                }

                // 将函数节点的字符串表示与全局符号文件中的函数进行比较，去除空白符
                let func_str = quote! { #func }.to_string();
                let func_str_no_whitespace = remove_whitespace(&func_str);
                if global_symbols.contains(&func_str_no_whitespace) {
                    // 如果函数节点的字符串表示在全局符号文件中出现过，跳过该函数
                    continue;
                }

                // 逐个遍历函数定义，替换同名函数
                let mut found = false;
                for (i, (existing_ident, _)) in function_definitions.iter_mut().enumerate() {
                    if *existing_ident == ident {
                        // 替换同名函数
                        function_definitions[i] = (ident.clone(), func.clone());
                        found = true;
                        break;
                    }
                }
                // 如果没有找到同名函数，直接插入
                if !found {
                    function_definitions.push((ident, func));
                }
            }
            Item::Struct(struct_item) => {
                // 获取结构体名
                let ident = struct_item.ident.to_string();
                // 如果已经遇到过这个结构体名，则过滤掉
                if seen_definitions.contains(&ident) {
                    //return false;
                    continue;
                }
                // 否则，标记为已遇到，并保留
                seen_definitions.insert(ident);
                //true
                other_definitions.push(Item::Struct(struct_item));
            }
            Item::Enum(enum_item) => {
                // 获取枚举名
                let ident = enum_item.ident.to_string();
                // 如果已经遇到过这个枚举名，则过滤掉
                if seen_definitions.contains(&ident) {
                    //return false;
                    continue;
                }
                // 否则，标记为已遇到，并保留
                seen_definitions.insert(ident);
                //true
                other_definitions.push(Item::Enum(enum_item));
            }
            Item::Type(type_item) => {
                // 获取类型定义名
                let ident = type_item.ident.to_string();
                // 如果已经遇到过这个类型定义名，则过滤掉
                if seen_definitions.contains(&ident) {
                    //return false;
                    continue;
                }
                // 否则，标记为已遇到，并保留
                seen_definitions.insert(ident);
                //true
                other_definitions.push(Item::Type(type_item))
            }
            Item::Static(static_item) => {
                // 获取全局变量名
                let ident = static_item.ident.to_string();
                // 如果已经遇到过这个全局变量名，则过滤掉
                if seen_definitions.contains(&ident) {
                    //return false;
                    continue;
                }
                // 否则，标记为已遇到，并保留
                seen_definitions.insert(ident);
                //true
                other_definitions.push(Item::Static(static_item));
            }
            Item::Macro(macro_item) => {
                // 获取宏定义名
                let ident = macro_item.ident.as_ref().map(|i| i.to_string()).unwrap_or_else(|| "".to_string());
                // 如果已经遇到过这个宏定义名，则过滤掉
                if seen_definitions.contains(&ident) {
                    //return false;
                    continue;
                }
                // 否则，标记为已遇到，并保留
                seen_definitions.insert(ident);
                //true
                other_definitions.push(Item::Macro(macro_item));
            }
            Item::Use(use_item) => {
                // 获取 use 语句的路径
                let use_tree = &use_item.tree;
                let use_path = format!("{:#?}", use_tree);
                // 如果已经遇到过这个 use 语句，则过滤掉
                if seen_use_statements.contains(&use_path) {
                    //return false;
                    continue;
                }
                // 否则，标记为已遇到，并保留
                seen_use_statements.insert(use_path);
                //true
                other_definitions.push(Item::Use(use_item));
            }
            _ => {
                //true, // 保留其他声明
                other_definitions.push(item);
            }
        }
    }

    // 将函数定义添加到最终的 filtered_items 中
    let mut final_items = Vec::new();

    // 将 use 语句提升到最前面
    for item in other_definitions.iter() {
        if let Item::Use(_) = item {
            final_items.push(item.clone());
        }
    }

    // 添加其他定义
    for item in other_definitions.iter() {
        if let Item::Use(_) = item {
            continue; // 跳过已经添加的 use 语句
        }
        final_items.push(item.clone());
    }

    // 添加非空且唯一的函数定义
    //let mut seen_functions = HashSet::new();

    //for (ident, func) in function_definitions {
    //    if !seen_functions.contains(&ident) {
    //        final_items.push(Item::Fn(func));
    //        seen_functions.insert(ident);
    //    }
    //}

    // 添加非空且唯一的函数定义，保留原始顺序，后面的同名函数覆盖前面的函数
    //let mut seen_functions = HashMap::new();
    //for (ident, func) in function_definitions {
    //    seen_functions.insert(ident, func);
    //}
    
    // 将函数定义添加到最终的 filtered_items 中，保留原始顺序
    for (_, func) in function_definitions {
        final_items.push(Item::Fn(func));
    }

    //for (_, func) in function_definitions {
    //    final_items.push(Item::Fn(func));
    //}

    // 生成新的 Rust 代码
    let output_code = quote! {
        #(#final_items)*
    };

    // 将过滤后的代码写入临时文件
    let mut temp_file = NamedTempFile::new().expect("Failed to create temp file!");
    writeln!(temp_file, "{}", output_code).expect("Failed to write code into temp file!");

    // 使用 rustfmt 格式化代码
    let temp_path = temp_file.path().to_str().unwrap();
    Command::new("rustfmt")
        .arg(temp_path)
        .status()
        .expect("Failed to call rustfmt");

    // 格式化生成的代码
    let formatted_code = fs::read_to_string(temp_path).expect("Failed to read back formatted file!");
    
    // 输出结果
    println!("{}", formatted_code);
}
